"""
Copyright 2012 Wieser Dietmar, Margit Mutschlechner.

This file is part of Multimedia Social Networking Platform.

Multimedia Social Networking Platform is free software: 
you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Multimedia Social Networking Platform is distributed
in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Multimedia Social Networking Platform.  
If not, see <http://www.gnu.org/licenses/>.

"""

import time
from msnp.service.network import logic
from msnp.service.network import sending
from msnp.service.network.model import PeerModel
from msnp.service.network.logic import GroupManagementLogic
from msnp.model.PTPModel import Group
from msnp.persistence import PersistenceController
from msnp.model import PTPModel
from msnp.service import synch
from threading import Thread
from msnp.logger import Logger
from msnp import gui

"""This module represents the interface to the network operations."""

############
## MYSELF ##
############

#represents the current peer
__mySelf = PeerModel.Peer()

def getMySelf():
    global __mySelf
    return __mySelf
    
def setMySelf(mySelf):
    global __mySelf
    __mySelf = mySelf
    
    
##################################
## INTERFACES EXTERN TO NETWORK ##
##################################

## message exchange

def hello(isLogin):
    """This function forwards the call to the hello function in the Sender module.
    
    Args:
        isLogin: A boolean determining whether the executed authentication is a registration or a login.
    """
    
    sending.Sender.hello(isLogin, None)


def forwardRingReport(ringReportEntries, fingerValidationDict, backupValidationDict, alreadyReceivedUsers, type):
    """This function forwards the call to the forwardRingReport function in the Sender module.
    
    Args:
        ringReportEntries: all collected RingReportEntry instances
        fingerValidationDict: a dictinary for validating the fingertables
        backupValidationDict: a dictinary for validating the backups
        alreadyReceivedUsers: a list of peers that already received the message
        type: the report type (defined in RingReportType)
    """
    
    sending.Sender.forwardRingReport(ringReportEntries, fingerValidationDict, backupValidationDict, alreadyReceivedUsers, type)


def sendPersonalMessage(receiverName, message):
    """This function generates, sends and stores a personal message
    
    Args:
        receiverName: the name of the receiver (string)
        message: the message to send (string)
    """
    
    timestamp = time.time()
    senderName = getMySelf().getMyIdentity().getName()
    senderRespIdentity = getMySelf().getMyIdentity()
    if getMySelf().isLowLevelPeer() == True:
        senderRespIdentity = getMySelf().getResponsibleSuperPeer()
    logic.ResponsibilityLogic.forwardPersonalMessage(receiverName, senderName, senderRespIdentity, message, timestamp)
    #generate chat message
    chatMessage = PTPModel.ChatMessage(senderName, message, timestamp, PTPModel.ChatMessageStatus.SENDING)
    PersistenceController.insertChatMessage(senderName, receiverName, chatMessage)


## media content

def pollMediaContentSinceLastSynch(groups):
    """This function generates a MediaContentThread instance and starts it.
    
    Args:
        groups: a list of Group instances
    """
    
    mediaContentThread = MediaContentThread(groups)
    mediaContentThread.start()
    
    
class MediaContentThread(Thread):
    """Thread to poll media contents from other peers.

    Attributes:
        __groups: a list of Group instances.
    """
    
    def __init__(self, groups):
        Thread.__init__(self)
        self.__groups = groups
    
    def run(self):
        """This method forwards the call to the pollMediaContentSinceLastSynch of the NetSynchController module."""
        
        Logger.info("try to poll media content since last synch")
        if self.__groups != None and len(self.__groups) > 0:
            synch.NetSynchController.pollMediaContentSinceLastSynch(self.__groups)


## PeerUpdate
    
def leaveNetwork():
    """This function forwards the call to the leaveNetwork function in the PeerUpdateLogic module.
    
    Returns:
        True if the leave was successful, False otherwise.
    """
    
    return logic.PeerUpdateLogic.leaveNetwork()


## GroupManagement

def getGroups(ownername, groupname, displayname, genre, reactType):
    """This function executes a group search.

    The function has to distinguish between a group search by owner or a complete search and between a low level peer and a super peer
    
    Args:
        ownername: the name of the owner (string)
        groupname: the name of the group (string)
        displayname: the displayname of the group (string)
        genre: the genre (string)
        reactType: determines how to react on the execution.
    """
    
    myIdentity = getMySelf().getMyIdentity()
    myName = myIdentity.getName()
    #search group by searching owner
    if ownername != None and len(ownername) > 0:
        if getMySelf().isLowLevelPeer():
            respSuperPeer = getMySelf().getResponsibleSuperPeer()
            sending.Sender.getGroupsWithOwner(respSuperPeer, myName, ownername, groupname, displayname, genre, reactType)
        else:
            GroupManagementLogic.getGroupsWithOwner(myIdentity, myName, ownername, groupname, displayname, genre, reactType)
    #search group sequentially through the ring
    else:
        if getMySelf().isLowLevelPeer():
            respSuperPeer = getMySelf().getResponsibleSuperPeer()
            sending.Sender.getGroupsWithoutOwner(respSuperPeer, myName, [], groupname, displayname, genre, reactType)
        else:
            GroupManagementLogic.getGroupsWithoutOwner(myIdentity, myName, [], groupname, displayname, genre, reactType)


def addAsMember(groupname, ownername):
    """This function adds the current user as new member to the given group.
    
    Args:
        ownername: the owner name (string)
        groupname: the group name (string)
    """
    
    # search for owner, he adds member and sends a callback
    myIdentity = getMySelf().getMyIdentity()
    membername = myIdentity.getName()
    ownername = membername if (ownername == "") else ownername
    if getMySelf().isLowLevelPeer():
        respSuperPeer = getMySelf().getResponsibleSuperPeer()
        sending.Sender.addMember(ownername, membername, groupname, respSuperPeer)
    else:
        GroupManagementLogic.addMember(ownername, membername, groupname, myIdentity)
    
    
def getGroupsIAmMember():
    """This function collects all groups where the current peer is a member of.
        
    Returns:
        Returns a list of Group instances.
    """
    
    myName = getMySelf().getMyIdentity().getName()
    if getMySelf().isLowLevelPeer():
        return sending.Sender.getGroupsForLowLevel(myName)
    else:
        return GroupManagementLogic.getGroupsForUsername(myName)


def getGroupsAndMessageCount():
    """This function collects all groups where current peer is a member of together with the number of already processed stored messages.
        
    Returns:
        Returns only already processed messages because the not processed once get put into the custody queue
        and the low level peer will process them.
    """
    
    myName = getMySelf().getMyIdentity().getName()
    if getMySelf().isLowLevelPeer():
        return sending.Sender.getGroupsAndMessageCountForLowLevel(myName)
    else:
        return GroupManagementLogic.getGroupsAndMessageCountForUsername(myName)
    
    
def establishGroup(groupname, displayname, description, genres):
    """This function establishes a new group.
    
    Args:
        groupname: the name of the group (string)
        displayname: the displayname of the group (string)
        description: the description of the group (string)
        genre: a list of genres
        
    Returns:
        Returns the group and a return value whether the establishment was successful or not.
    """
    
    myName = getMySelf().getMyIdentity().getName()
    if displayname == "":
        displayname = groupname
    group = Group(groupname, myName, displayname, description, genres, 1)
    if getMySelf().isLowLevelPeer():
        return sending.Sender.establishGroupForLowLevel(group)
    else:
        return GroupManagementLogic.establishGroup(group)


def changeGroupDetails(groupname, displayname, description, genres, isActive):
    """This function changes group details.
    
    Args:
        groupname: the name of the group (string)
        displayname: the displayname of the group (string)
        description: the description of the group (string)
        genre: a list of genres
        isActive: A boolean value, True if the group is active, False otherwise
        
    Returns:
        Returns whether the update was successful or not.
    """
    
    myName = getMySelf().getMyIdentity().getName()
    if displayname == None or len(displayname) == 0:
        displayname = groupname
    group = Group(groupname, myName, displayname, description, genres, isActive)
    if getMySelf().isLowLevelPeer():
        return sending.Sender.changeGroupDetailsForLowLevel(group)
    else:
        return GroupManagementLogic.changeGroupDetails(group)
    
    
def changeMemberStatus(membername, groupname, ownername, status):
    """This function changes the membership status.
    
    Args:
        membername: the member name (string)
        groupname: the group name (string)
        ownername: the owner name (string)
        status: the membership status (defined in MemberStatus)
    """
    
    myName = getMySelf().getMyIdentity().getName()
    ownername = myName if (ownername == "") else ownername
    if getMySelf().isLowLevelPeer():
        respIdentity = getMySelf().getResponsibleSuperPeer()
        sending.Sender.setMemberStatus(respIdentity, myName, membername, groupname, ownername, status)
    else:
        myIdentity = getMySelf().getMyIdentity()
        GroupManagementLogic.setMemberStatus(myIdentity, myName, membername, groupname, ownername, status)


def getStoredMessages():
    """This function forwards the call to the executeGetStoredMessages function of the GroupManagementLogic module."""
    
    GroupManagementLogic.executeGetStoredMessages()


def getGroupsWithMembersToConfirm():
    """This function collects the groups of the current peer where at least one member has the status NOT_CONFIRMED.
    """
    
    myName = getMySelf().getMyIdentity().getName()
    if getMySelf().isLowLevelPeer():
        groups = sending.Sender.getGroupsWithMembersToConfirmForLowLevel(myName)
    else:
        groups = PersistenceController.selectGroupsWithMembersToConfirm(myName)
    gui.MySignal.emitGroupsWithMembersToConfirmSignal(groups)
